import GameConfig from "./config/GameConfig";
import { MusicManager } from "./MusicManager";
import PhysicsManager from "./PhysicsManager";
import { SDKBase, UserInfo } from "./sdk/SDKBase";
import StaticInstance from "./StaticInstance";
import DataStorage from "./utils/DataStorage";
import SDKUtil from "./utils/SDKUtil";

const { ccclass, property } = cc._decorator;

/**
 * 关卡配置信息
 */
interface IMidConfig {
    level: number,
    count: number,
    node: cc.Node
}

@ccclass
export default class GameManager extends cc.Component {

    @property(cc.Node)
    bowl: cc.Node = null
    @property(cc.SpriteFrame)
    openEyeBowl: cc.SpriteFrame = null
    @property(cc.SpriteFrame)
    closeEyeBowl: cc.SpriteFrame = null

    @property({
        type: [cc.Prefab],
        displayName: '食物预制体'
    })
    foodPrefabs: cc.Prefab[] = []

    @property(cc.Node)
    foodsRoot: cc.Node = null   // 食物根节点

    // WX Test:
    @property(cc.Label)
    nickNameLabel: cc.Label = null

    sdk: SDKBase = null
    private readonly speed: number = 200

    // 当前关卡和食物节点的数据
    midConfig: IMidConfig = {
        level: 0,
        count: 0,
        node: null
    }

    // 检测频率
    time: number = 0
    readonly checkCD: number = 0.3   // 检测cd

    isPlaying: boolean = false

    /**
     * 所有食物刚体是否都静止
     */
    get allBodyStop(): boolean {
        for (let i = 0; i < this.foodsRoot.childrenCount; i++) {
            const food = this.foodsRoot.children[i]
            const body = food.getComponent(cc.RigidBody)
            // 判断线性速度是否趋近于0,0
            if (!body.linearVelocity.fuzzyEquals(cc.v2(0, 0), 0.1)) {
                return false
            }
        }
        return true
    }

    /**
     * 检测已有食物是否还有静态刚体，用于判断是否有食物未落下
     */
    get someBodyStatic(): boolean {
        for (let i = 0; i < this.foodsRoot.childrenCount; i++) {
            const food = this.foodsRoot.children[i]
            const body = food.getComponent(cc.RigidBody)
            // 判断是否为静态刚体
            if (body.type === cc.RigidBodyType.Static) {
                return true
            }
        }
        return false
    }

    /**
     * 当前食物类型
     */
    get nowFoodType(): number {
        return GameConfig[this.midConfig.level - 1][this.midConfig.count]
    }

    /**
     * 是否能继续添加食物
     */
    get canAddFood(): boolean {
        const len = GameConfig[this.midConfig.level - 1].length
        if (this.midConfig.count >= len) {
            return false
        }

        return true
    }

    onLoad() {
        StaticInstance.setGameManager(this)
        PhysicsManager.openPhysicsSystem()  // 开启物理系统
        console.log(`GameManager onLoad`)
        // 播放背景音乐
        MusicManager.getInstance().playBGM()

    }

    async start() {
        //WX Test:
        // 获取用户信息
        let userInfo: UserInfo = DataStorage.getUserInfo()  // 本地获取
        this.sdk = SDKUtil.getSDK()
        if (this.sdk) {
            this.sdk.init()
        }
        if (!userInfo) {
            // 本地没有用户信息
            // 通过平台sdk授权，获取用户信息
            if (this.sdk) {
                userInfo = await this.sdk.getUserInfo()
            }
        }
        if (userInfo) {
            console.log('userInfo:', userInfo)
            this.nickNameLabel.string = '昵称：' + userInfo.nickName
            DataStorage.setUserInfo(userInfo)   // 保存用户信息
        } else {
            console.warn('获取用户信息失败')
        }

    }

    // WX: Test
    onShare() {
        if (!this.sdk) { return }
        this.sdk.share()
    }

    update(dt: number) {
        this.time += dt
        if (this.isPlaying && this.time >= this.checkCD) {
            this.time = 0
            // 检测是否有食物落下，并且生成新的食物
            // console.log('check')
            this.checkAllBody()
            // 失败检测
            this.checkFall()
        }
    }

    public startGame(level: number) {
        console.log(`GameConfig:`, GameConfig)

        this.showBowl()

        // 记录当前关卡信息
        this.midConfig.level = level
        this.midConfig.count = 0
        // 从配置表获取食物数据
        const food = this._addFood(this.nowFoodType)
        this.midConfig.node = food

        this.isPlaying = true
    }

    public onRotateFood(angle: number) {
        // console.log(`[GameManager] angle:`, angle)
        if (!this.midConfig.node) { return }
        const food = this.midConfig.node
        food.angle = angle
    }

    public onClickLeftFood(dt: number) {
        if (!this.midConfig.node) { return }
        const food = this.midConfig.node
        food.x -= this.speed * dt
    }

    public onClickRightFood(dt: number) {
        if (!this.midConfig.node) { return }
        const food = this.midConfig.node
        food.x += this.speed * dt
    }

    /**
     * 下落-点击事件
     */
    public onClickDownFood(): void {
        if (!this.midConfig.node) { return }
        const food = this.midConfig.node
        PhysicsManager.setRigidBodyDynamic(food)
        PhysicsManager.setRigidBodyLinearVelocity(food, cc.v2(0, -5))   // 线性速度
        this.midConfig.node = null  //将node设为null，可以防止在下落过程中继续操作食物
    }

    /**
     * 显示碗
     */
    public showBowl() {
        this.bowl.active = true
        this.bowl.stopAllActions()
        // 执行眨眼动画
        cc.tween(this.bowl).repeatForever(
            cc.tween()
                .delay(2).call(() => {
                    const bowlSpriteComp = this.bowl.getComponent(cc.Sprite)
                    bowlSpriteComp.spriteFrame = this.closeEyeBowl
                })
                .delay(0.3).call(() => {
                    const bowlSpriteComp = this.bowl.getComponent(cc.Sprite)
                    bowlSpriteComp.spriteFrame = this.openEyeBowl
                })
        ).start()
    }

    public hideBowl() {
        this.bowl.active = false
    }

    /**
     * 添加食物到游戏中
     * @param index 
     */
    private _addFood(index: number): cc.Node {
        const foodNode = cc.instantiate(this.foodPrefabs[index])
        const pos = cc.v2(0, 450)   // 食物初始位置
        this.foodsRoot.addChild(foodNode)
        foodNode.setPosition(pos)
        PhysicsManager.setRigidBodyStatic(foodNode) // 设置食物节点默认为静态刚体，不让其自动下落
        this.midConfig.count += 1
        this.updateLevelInfo()
        return foodNode
    }

    /**
     * 更新关卡左上角信息
     */
    updateLevelInfo() {
        const level = this.midConfig.level
        const nowItem = this.midConfig.count
        const allNum = GameConfig[this.midConfig.level - 1].length
        console.log('this.midConfig.level:', this.midConfig.level)
        StaticInstance.uiManager.setLevelInfo(level, nowItem, allNum)
    }

    /**
     * 检测所有食物刚体，并且在食物下落后生成新食物
     */
    checkAllBody() {
        if (this.someBodyStatic || !this.allBodyStop) { return }

        if (!this.canAddFood) {
            console.log('can not add food')
            // 游戏结束
            this.isPlaying = false
            // this.bowl.active = false
            // 游戏胜利
            if (this.midConfig.level < 6) {
                StaticInstance.uiManager.showWinPanel() // 常规胜利面板
            } else {
                StaticInstance.uiManager.showWinByLastPanel()   // 最后一关的胜利面板，没有下一关按钮
            }
            MusicManager.getInstance().playWinEffect()  // 胜利音效
            // 保存解锁关卡
            DataStorage.setUnLockLevel(this.midConfig.level + 1)
            return
        }

        console.log('allBodyStop:', this.allBodyStop)
        this.midConfig.node = this._addFood(this.nowFoodType)
    }

    /**
     * 检测食物是否落出碗外，并判断游戏失败
     */
    checkFall() {
        let hasFall: boolean = false
        for (let i = 0; i < this.foodsRoot.childrenCount; i++) {
            const node = this.foodsRoot.children[i]
            // 掉出屏幕
            if (node.y <= -800) {
                node.destroy()
                hasFall = true
                break
            }
        }

        if (hasFall) {
            // 游戏失败
            console.log('game loss')
            this.isPlaying = false
            StaticInstance.uiManager.showLosePanel()
            MusicManager.getInstance().playLoseEffect() // 失败音效
        }
    }

    /**
     * 下一关-点击事件
     */
    public onClickNextLevel() {
        this.clearAllFood()
        // 判断最后一关
        if (this.midConfig.level >= 6) {
            // 不做任何事情
            return
        }
        this.midConfig.level += 1
        StaticInstance.uiManager.startGame(this.midConfig.level)
    }

    /**
     * 再来一次-点击事件
     */
    public onClickPlayAgain() {
        this.clearAllFood()
        StaticInstance.uiManager.startGame(this.midConfig.level)
    }

    /**
     * 清空所有食物
     */
    public clearAllFood() {
        this.foodsRoot.removeAllChildren()
    }
}
